
; UCSD PASCAL I.5 INTERPRETER (FILE "rxboot.mac")


         .NLIST  TTM
         .TITLE  FLOPPY BOOTSTRAP
         ;
         ; COPYRIGHT (C) 1978 REGENTS OF THE UNIVERSTIY OF CALIFORNIA.
         ; PERMISSION TO COPY OR DISTRIBUTE THIS SOFTWARE OR DOCUMEN-
         ; TATION IN HARD COPY OR SOFT COPY GRANTED ONLY BY WRITTEN LICENSE
         ; OBTAINED FROM THE INSTITUTE OF INFORMATION SYSTEMS.  ALL RIGHTS
         ; RESERVED.  NO PART OF THIS PUBLICATION MAY BE REPRODUCED, STORED
         ; IN A RETRIEVAL SYSTEM ( E.G., IN MEMORY, DISK, OR CORE) OR BE
         ; TRANSMITTED BY ANY MEANS, ELECTRONIC, MECHANICAL, PHOTOCOPY,
         ; RECORDING, OR OTHERWISE, WITHOUT PRIOR WRITTEN PERMISSION FROM THE
         ; PUBLISHER.
         ;
         ;

 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;    PDP-11 PASCAL SYSTEM BOOTSTRAP LOADER
 ;  THIS CODE SITS ON BLOCKS 0 & 1 OF THE
 ;  FLOPPY AND IS READ INTO LOW CORE BY THE
 ;  HARDWARE LOADER.  CONTROL THEN PASSES TO
 ;  ADDRESS 0 WHERE WE TAKE OVER.  NOTE THAT
 ;  R0 = DRIVE # WE WERE LOADED FROM (0 OR 1)
 ;  ALSO ONLY THE FIRST 128 BYTES ARE LOADED BY
 ;  HARDWARE.  THE REST HAS TO BE DONE OURSELVES
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 RELOC   = 32000         ; ADDRESS WHERE THE CODE COPIES ITSELF TO
                         ; AND ACTUALLY RUNS...HENCE THE ASECT GROSSNESS
 BK = %2
 BASE = %3
 IPC= %4
 MP = %5
 R0 = %0
 R1 = %1
 R2 = %2
 R3 = %3
 R4 = %4
 R5 = %5
 SP = %6
 PC = %7
 DATASZ  = -10   ; INDEX TO LOCAL DATA SIZE IN JTAB
 SYSUNT  = 404   ; ADDRESS OF SYSUNT WORD IN SYSCOM
 SEG     = 422   ; SEG ADDR IN SYSCOM
 SEGTBL  = 540
 MEMTOP = 424
 FSTBLK  = 2     ; DIR ENTRY INDEX FOR DFIRSTBLK
 DTID    = 6     ;  "    "     "  FOR TITLE FIELD
 DELENG  = 26.   ; LENGTH IN BYTES OF EACH DIR ENTRY
 KW11    = 177546
 RXCS    = 177170
 RCSR    = 177560
 RBUF    = 177562
 XCSR    = 177564
 XBUF    = 177566
 CR = 15
 LF = 12
 BUZZ = 07

         .ASECT
 . = RELOC

 ;  THESE FIRST 128 BYTES ARE REALLY LOADED AT WORD 0
 ;  AND MUST READ IN THE REST OF THE SYSTEM
 ;  WHAT IS DONE HERE IS TO READ THE WHOLE BOOTSTRAP
 ;  INTO THE RELOCATE POSITION FOR ACTUAL EXECUTION.

 ENTRY:  NOP                     ; BOOT LOADER WANTS THIS HERE
         MOV     #1000,SP        ; SET UP STACK...NO 4-TRAP HANDLING YET
         MOV     R0,-(SP)        ; SAVE R0 FOR LATER CHECK AFTER START
         BEQ     2$              ; SKIP BIS...NO 10-TRAP EITHER
         BR      1$              ; ELSE SET PROPER UNIT #
         .WORD   TRWAIT-RELOC    ; WAIT ON TR BIT FOR RX (BPT OP)
         .WORD   340
         .WORD   DNWAIT-RELOC    ; WAIT ON DONE BIT (IOT OP)
         .WORD   340
 1$:     BIS     #20,RXMASK      ; UNIT WORD, SO SET UNIT 1 BIT IF R0 <> 0
 2$:     MOV     #RELOC,R0       ; BUFFER ADDRESS FOR RXREAD
         MOV     #8.,R1          ; NUMBER OF SECTORS TO READ
         CLR     R2              ; LOGICAL SECTOR NUMBER
         MOV     #START,-(SP)    ; TRICKY JSR TO SAVE A WORD (HARD UP)
 RXREAD: ; DUMB IO ROUTINE FOR SYSTEM LOADER
         MOV     R2,-(SP)        ; SAVE LSN FOR LATER
 RXLOOP: MOV     #RXCS,R4        ; R4 POINTS AT RXCS
         IOT     ; WAIT UNTIL DONE
         MOV     R4,R5           ; SET UP TO POINT R5 AT RXCS+2...RXDB
         MOV     RXMASK,(R5)+    ; SEND READ SECTOR COMMAND
         MOV     (SP),R3         ; SET UP FOR SECTOR AND TRACK CALC
         JSR     PC,@RXCALC      ; HERE IT IS...THE GROSSEST THING EVER
         BPT     ; WAIT UNTIL TR
         MOV     R3,(R5)         ; SEND SECTOR ADDRESS
         BPT     ; WAIT UNTIL TR
         MOV     R2,(R5)         ; SEND TRACK ADDRESS
         IOT     ; WAIT UNTIL DONE
         MOV     #128.,R3        ; LOOP COUNTER FOR MOVB
         MOV     (PC),(R4)       ; SEND EMPTY BUFFER COMMAND
 1$:     BPT     ; WAIT UNTIL TR (BPT IS 03, EMPTY BUFF COMMAND, YUK)
         MOVB    (R5),(R0)+
         DEC     R3              ; DEC LOOP COUNTER...128 MOVB DONE
         BNE     1$              ; IF = 0
         INC     (SP)            ; BUMP LOGICAL SECTOR #
         DEC     R1              ; NUMBER OF SECTORS TO READ
         BNE     RXLOOP
         MOV     (SP)+,R2        ; RESTORE UPDATED SECTOR ADDRESS
         RTS     PC              ; SO R0 (ADDRESS) AND R2 (SECTOR) ARE UPDATED

 RXMASK: .WORD   7               ; READ SECTOR COMMAND
 RXCALC: .WORD   RXDUMB-RELOC    ; ADDR OF TRACK SECT CALC ROUTINE

 RXDUMB: ; THIS ROUTINE FIGURES AN ACTUAL SECTOR FROM LSN IN R3
         ; IT IS USED ONLY TO LOAD REMAINDER OF BOOTSTRAP. AFTER
         ; THAT RXCALC IS MADE INTELLIGENT AND WE GO INTO THE OZONE
         MOV     #1,R2           ; RETURN TRACK #1 (FLOPPY CONVENTION)
         ASL     R3              ; DOUBLE IT FOR 2 INTERLEAVE
         INC     R3              ; AND STAGGER BY 1 (FLOPPY CONVENTION)
         RTS     PC              ; BACK TO RXREAD

 TRWAIT: TSTB    (R4)            ; CHECK TR BIT
         BEQ     TRWAIT          ; AS LONG AS ZERO, NOT DONE OR TR
         BPL     HALTER          ; DONE BIT RATHER THAN TR...BOMBOUT
 DORTI:  MOV     (SP)+,@SP
         RTS     PC


 DNWAIT: TST     (R4)            ; WAIT UNTIL DONE BIT (NOT TR)
         BEQ     DNWAIT          ; SO LOOP AS LONG AS RXCS = 0
         BPL     DORTI           ; DO AN RTI BACK TO RXREAD
 HALTER: HALT
         BR      HALTER

 ;  PAST THIS POINT IS THE CODE LOADED BY THE FIRST 128
 ;  BYTES.  THIS INCLUDES MISC ROUTINES AND SYSTEM STARTUP

 RXSMRT: MOV     #8.,R2          ; LOOP COUNT
 1$:     CMP     #6400,R3        ; DOES 26 GO INTO DIVIDEND?
         BHI     2$              ; BRANCH IF NOT, C CLEAR
         ADD     #171400,R3      ; SUBTRACT 26 FROM DIVIDEND, SETS C
 2$:     ROL     R3              ; SHIFT DIVIDEND AND QUOTIENT
         DEC     R2              ; DEC LOOP COUNT
         BGT     1$              ; BRANCH TILL DIVIDE DONE
         MOVB    R3,R2           ; COPY TRACK NUMBER
         CLRB    R3              ; REMOVE TRACK NUMBER FROM REMAINDER
         SWAB    R3              ; GET REMAINDER
         CMP     #12.,R3         ; C=1 IF 13<=R3<=25, ELSE C=0
         ROL     R3              ; DOUBLE FOR 2 TO 1 INTERLEAVE
                                 ; C-BIT COMES IN FOR SECTOR GROUP
         ASL     R2              ; ADD TRACK TO TRACK SKEW TO SECTOR
         ADD     R2,R3           ; SKEW BY 2* TRACK
         ADD     R2,R3           ; SKEW BY 4* TRACK
         ADD     R2,R3           ; SKEW BY 6* TRACK
         ASR     R2              ; REFIX TRACK NUMBER
         INC     R2              ; PUT TRACK # IN RANGE 1-76 TO HANDLE
                                 ; ANSI FLOPPY, TRACK 0 IS LEFT ALONE
 3$:     SUB     #26.,R3         ; MODULO SECTOR INTO RANGE -26,-1
         BGE     3$              ; LOOP TILL REMAINDER GOES NEGATIVE
         ADD     #27.,R3         ; PUT SECTOR IN RANGE 1,26
         RTS     PC              ; AND RETURN TO RXREAD

 BOMB:   MOVB    (R0)+,R1
         BMI     XBOMB           ; IF MINUS IN STRING, RETURN
         BEQ     HALTER
 1$:     TSTB    @#XCSR          ; WAIT UNTIL DL11 DONE BIT
         BPL     1$
         MOVB    R1,@#XBUF
         BR      BOMB
 XBOMB:  ROR     R0              ; RETURN TO USER...WORD BOUND R0
         ADC     R0
         ROL     R0
         RTS     R0
									
 NOCORE: JSR     R0,BOMB
         .ASCIZ  <CR><LF><BUZZ>'?NOT ENOUGH CORE TO BOOT?'<CR><LF>
         .EVEN

 DIRSRCH:MOV     #DIREC+DTID,R1  ; R1 POINTS AT DTID OF EACH DIR ENTRY
 DIRLOOP:MOV     R1,R4           ; R4 IS USED FOR TITLE COMPARE
         MOV     R0,R3           ; R3 IS TITLE TO LOOK FOR (IN CODE STREAM)
         MOVB    @R0,R2          ; NUMBER OF BYTES IN NAME (STRING VAR)
 1$:     CMPB    (R3)+,(R4)+     ; CHECK EACH BYTE FOR EQUAL
         BNE     2$              ; WOOPS, NEQ...CHECK NEXT ENTRY OR BOMB
         DEC     R2              ; OK SO FAR...DECREMENT LOOP COUNTER
         BPL     1$              ; LOOP FOR LENG+1 CHARS
         ; EUREKA! WE HAVE FOUND IT...RETURN WITH R1 POINTING AT ENTRY
         SUB     #DTID,R1        ; RETURN R1 AT START OF ENTRY
         ADD     #18.,R0         ; POINT R0 PAST STRING IN CODE
         RTS     R0              ; AND RETURN
 2$:     ADD     #DELENG,R1      ; SKIP R1 TO NEXT DIRECTORY ENTRY
         CMP     R1,#ENDDIR      ; CHECK IF WE HAVE GONE OFF END OF DIR
         BLO     DIRLOOP         ; IF NOT, CHECK NEXT ENTRY
         JSR     R0,BOMB         ; OH WELL, NO SYSTEM FILE...TIME TO CROAK
         .ASCII  <CR><LF><BUZZ>'?YOU DON'<47>'T HAVE A '<200>
         .EVEN
         INC     R0              ; SKIP R0 PAST LENGTH BYTE
         BR      BOMB            ; USE R0 AS IS FOR REST OF MESSAGE

 START:  TST     (SP)+           ; GRAB OLD UNIT # FROM ENTRY
         BEQ     1$              ; SO SKIP OVER UNIT 1 STUFF
         BIS     #20,RXMASK      ; SET THE UNIT 1 BIT IN IO MASK
 1$:     MOV     #DIREC,SP       ; OUR NEW STACK LOCATION
         MOV     #NOCORE,@#4     ; BOMB SYSTEM IF NO CORE
         MOV     #RXSMRT,RXCALC  ; NOW WE CAN USE THE DISK OK
         MOV     #TRWAIT,@#14    ; RELOCATE THIS STUFF
         MOV     #DNWAIT,@#20    ; PROPERLY RELOCATED
         MOV     #16.,R1         ; READ DIRECTORY...NUMBER OF SECTORS
         JSR     PC,RXREAD       ; R0 AND R2 ARE STILL OK FROM LAST TIME
         JSR     R0,DIRSRCH      ; FIND THE CODE FILE FOR THE SYSTEM
         .ASCIZ  <15>'SYSTEM.PASCAL?'<CR><LF>
         MOV     (R1)+,FSTSYS    ; SAVE FIRST BLOCK FOR SYSTEM CODE
         JSR     R0,DIRSRCH      ; NOW LOOK FOR THE INTERPRETER .SAV FILE
         .ASCIZ  <15>'SYSTEM.PDP-11?'<CR><LF>
         MOV     (R1)+,R2        ; FIRST DISK ADDR OF INTERPRETER
         ASL     R2              ; MULTIPLY BY FOUR TO GET LSN
         ASL     R2
         MOV     @R1,R1          ; GET LAST BLOCK # OF INTERP
         INC     R1              ; MAKE IT POINT AT ALL BLOCKS
         ASL     R1              ; MULTIPLY BY 4
         ASL     R1
         SUB     R2,R1           ; NOW R1 IS TOTAL SECTORS IN INTERP
         MOV     R1,-(SP)        ; SAVE THIS SECTOR COUNT FOR LATER
         MOV     #DIREC,R0       ; READ FIRST SECTOR INTO HIGH CORE
         MOV     #1,R1           ; TO SAVE TRAP VECTOR
         JSR     PC,RXREAD       ; NOW READ IN FIRST SECTOR
         MOV     #200,R0         ; NEXT READ IN REMAINDER OF INTERP
         MOV     (SP)+,R1        ; AGAIN TOTAL LENGTH IN SECTORS
         DEC     R1              ; BUT SUBTRACT THE ONE WE HAVE

         JSR     PC,RXREAD
         MOV     #TSTTRP,@#4     ; NOW FIND HIGHEST CORE FOR SP
 TSTLOOP:TST     (R0)+           ; START SKIPPING THROUGH MEMORY
         BR      TSTLOOP         ; UNTIL 4 TRAP TAKES US AWAY
 BADSYS: JSR     R0,BOMB         ; GO HERE TO CROAK FOR BAD CODE FILE
         .ASCIZ  <CR><LF><BUZZ>'?YOUR SEGTBL IS RIDICULOUS?'<CR><LF>
         .EVEN
 TSTTRP: SUB     #4,R0           ; BRING R0 BACK DOWN TO EARTH
         MOV     R0,SEG          ; HIGHEST MEM ADDR
         ; NOW READ SYSTEM CODE STUFF
         MOV     #LSEGTBL,R0     ; MEM ADDR TO RXREAD INTO
         MOV     #1,R1           ; NUMBER OF 128 SECTOR TO READ
         MOV     FSTSYS,R2       ; BLOCK NUMBER OF SYSCODE
         ASL     R2              ; MULTIPLY BY 4
         ASL     R2              ; TO END UP WITH RX LOGICAL SECTOR #
         JSR     PC,RXREAD       ; DO IO...READ IN SEGTBL FROM SYSCODE
         MOV     #4,SYSUNT       ; INFORM SYSTEM WHICH UNIT WAS LOADED FROM
         CMP     RXMASK,#7       ; NOW CHECK IF UNIT WAS RIGHT HAND DRIVE
         BEQ     3$              ; SKIP IF OUR IO WORD IS FOR LEFT UNIT
         MOV     #5,SYSUNT       ; IF RIGHT DRIVE, CHANGE UNIT TO # 5
 3$:     MOV     #LSEGTBL,R0     ; NOW COPY LOCAL TBL INTO SYSTEM TABLE
         MOV     #SEGTBL,R1      ; AND RELOCATE DISK ADDRS
         MOV     #16.,R2         ; FOR ALL 16 SEGS...LOOP COUNT
 TBLCPY: MOV     SYSUNT,(R1)+    ; COPY OVER BOOTED UNIT
         MOV     FSTSYS,@R1      ; PUT BASE FILE ADDR OF SYSTEM INTO TABLE
         ADD     (R0)+,(R1)+     ; ADD IN RELATIVE...NOW ABSOLUTE DK ADDR
         MOV     (R0)+,(R1)+     ; COPY BYTE COUNT TOO
         DEC     R2              ; DONE LOOP 16 TIMES?
         BNE     TBLCPY          ; GO LOOP IF NOT
         ; NOW READ IN SEG #0 OF SYSTEM CODE INTO HIGH CORE
         MOV     SEG,R0          ; GET HIGHEST MEM ADDR AGAIN!
         SUB     SEGTBL+4,R0     ; OPEN GAP @R0 BIG ENOUGH FOR SYSCODE
         TST     (R0)+           ; SEG POINTS @ LAST WORD...NOT ABOVE
         MOV     R0,NEWSP        ; STASH THE NEW STACK TOP
         MOV     #77777,R1       ; NUMBER OF SECTORS TO READ
         MOV     SEGTBL+2,R2     ; FINALLY GET DISK BLOCK AND
         ASL     R2              ; MAKE A LSN
         ASL     R2
         MOV     #AHEAD,@#4      ; TRAP TO STOP DISK READ
         JSR     PC,RXREAD       ; READ IN SYSTEM CODE FILE
 AHEAD:  BIT     #40,@#RXCS      ; IS DONE BIT ON?
         BNE     1$
         TSTB    @#RXCS+2        ; GRAB THE LEFT OVER BYTE
         BR      AHEAD
 1$:     MOV     NEWSP,SP        ; NEW STACK POINTER JUST BELOW SYSCODE
         MOV     #64.,R2         ; NOW FINAL INITIALIZE...COPY VECTOR STUFF
         CLR     R1              ; COPY 128 BYTES FROM HIGH CORE TO LOW
         MOV     #DIREC,R0
 2$:     MOV     (R0)+,(R1)+     ; COPY EACH WORD OF FIRST SECTOR
         DEC     R2
         BNE     2$
         MOV     @#4,-(SP)       ; SAVE 4-TRAP THING FOR KW11 TEST
         MOV     #NOKW11,@#4     ; SET UP TO ENABLE INTERRUPTS ON CLOCK
         BIS     #100,@#KW11     ; ENABLE INTERRUPT...IF NO CLOCK THEN TRAP
         SUB     #4,SP           ; KW11 RUNNING...MAKE STACK LOOK LIKE TRAPPED
 NOKW11: ADD     #4,SP           ; CHUCK GARBAGE ON STACK
         MOV     (SP)+,@#4       ; RESTORE INTERP 4 TRAP HANDLER
         ; NOW SET UP REGISTERS FOR ENTRY VIA CBP 1 .  WE WANT OUTER
         ; BLOCK OF SYSTEM TO HAVE STAT&DYN LINKS POINT TO ITSELF.
         ; THIS ENABLES TESTING FOR STACK UNDERFLOWS.
         MOV     SEG,R0          ; POINT R0 AT JTAB FOR OUTER BLOCK
         MOV     R0,MEMTOP
         SUB     -(R0),R0        ; SUBTRACT SELF RELATIVE
         MOV     SP,MP           ; SET MP TO WHERE IT WILL BE AFTER CBP
         SUB     DATASZ(R0),MP   ; OPEN GAP FOR UNIVERSAL LEVEL VARS
         MOV     #400,@MP        ; FUNNY PARAM FOR SYSTEM OUTER BLOCK
         SUB     #14,MP          ; LEAVE MP AT ITS FINAL LOCATION
         MOV     MP,BASE         ; BASE SHOULD POINT HERE TOO.
         MOV     #CBP.1,IPC      ; SET UP IPC FOR CBP CALL OF OUTER BLOCK
         BIS     #100,@#RCSR     ; ENABLE KEYBOARD INTERRUPTS
         MOV     @#40,BK         ; WORD 40 HAS BACK ADDRESS
         CLR     -(SP)           ; SO PR = 0 UPON ENTRY
         MOV     BK,-(SP)        ; PC FOR RTI...ENTR SYSTEM AT BACK
         RTI                     ; NOW START...FETCH CBP 1 OPCODE

 FSTSYS: .WORD   ; DISK ADDR (BLOCK) OF PASCAL SYSTEM CODE
 NEWSP:  .WORD   ; STACK POINTER WE COMPUTE
 CBP.1:  .BYTE   128.+66.,1      ; OUTER BLOCK CALLING SEQUENCE

 DIREC   = RELOC+1024.
 ENDDIR  = DIREC+2048.   ; ROOM FOR 4 BLOCK DIRECTORY
 LSEGTBL = DIREC+128.    ; DONT DESTROY LOW CORE IMAGE

         .END    ENTRY

; +------------------------------------------------------------------+
; |                                                                  |
; |                     F     I     N     I     S                    |
; |                                                                  |
; +------------------------------------------------------------------+
